{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 使用 torch.Tensor来处理数据\n",
    "\n",
    "Tensor就是pytorch中存储数据的主要格式，跟numpy类似"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里，我们先介绍一些最基本的操作和常用的功能"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import torch # 导入torch包\n",
    "import numpy as np # 导入numpy包"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "-0.0806  0.1469  0.8234\n",
      "-0.0606 -0.6344 -0.8300\n",
      "[torch.FloatTensor of size 2x3]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 创建一个随机的二维数组（矩阵）\n",
    "exam1 = torch.randn(2, 3)\n",
    "print(exam1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " 0  0  0\n",
      " 0  0  0\n",
      "[torch.FloatTensor of size 2x3]\n",
      "\n",
      "\n",
      " 1  1  1\n",
      " 1  1  1\n",
      "[torch.FloatTensor of size 2x3]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 跟numpy一样，我们可以构造初始化为0、1的数组\n",
    "exam2 = torch.zeros(2, 3)\n",
    "\n",
    "exam3 = torch.ones(2, 3)\n",
    "\n",
    "print(exam2)\n",
    "\n",
    "print(exam3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " 1  2  4\n",
      " 2  3  6\n",
      "[torch.FloatTensor of size 2x3]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 当然，我们也可以直接从python的数组直接构造\n",
    "exam4 = torch.Tensor([[1, 2, 4], [2, 3, 6] ])\n",
    "print(exam4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "numpy 通常是通过 .shape 来获取数组的形状，但是对于torch.Tensor，我们使用的是 .size()\n",
    "\n",
    "对得到的变量进行访问，可以采取访问列表的方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'torch.Size'>\n",
      "2\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "shape = exam4.size()\n",
    "print(type(shape))\n",
    "print(shape[0])\n",
    "print(shape[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有时候，我们需要对数组形状进行改变，我们可以采用 .view() 的方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " 1  2\n",
      " 4  2\n",
      " 3  6\n",
      "[torch.FloatTensor of size 3x2]\n",
      "\n",
      "\n",
      " 1  2  4  2  3  6\n",
      "[torch.FloatTensor of size 1x6]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "exam5 = exam4.view(3, 2)\n",
    "\n",
    "# -1表示的是系统自动补齐\n",
    "exam6 = exam4.view(1, -1)\n",
    "\n",
    "print(exam5)\n",
    "print(exam6)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "torch.Tensor 支持大量的数学操作符 + , - , * , / 都是可以用的。\n",
    "\n",
    "当然也可以用Tensor内置的 add() 等, 这里需要提一下的就是 add 和 add_ 的区别\n",
    "\n",
    "使用add函数会生成一个新的Tensor变量， add_ 函数会直接再当前Tensor变量上进行操作\n",
    "\n",
    "所以，对于函数名末尾带有\"_\" 的函数都是会对Tensor变量本身进行操作的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "-0.0806  0.1469  0.8234\n",
      "-0.0606 -0.6344 -0.8300\n",
      "[torch.FloatTensor of size 2x3]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "exam1.add(20)\n",
    "print(exam1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " 19.9194  20.1469  20.8234\n",
      " 19.9394  19.3656  19.1700\n",
      "[torch.FloatTensor of size 2x3]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "exam1.add_(20)\n",
    "print(exam1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于常用的矩阵运算Tensor也有很好的支持"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "exam7:  \n",
      " 1  2  3\n",
      " 4  5  6\n",
      "[torch.FloatTensor of size 2x3]\n",
      "\n",
      "exam8:  \n",
      " 0.2148  0.1832  1.1225\n",
      "-0.1068  0.9847 -0.2159\n",
      "[torch.FloatTensor of size 2x3]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "exam7 = torch.Tensor([[1, 2, 3], [4, 5, 6]])\n",
    "exam8 = torch.randn(2, 3)\n",
    "\n",
    "print(\"exam7: \" , exam7)\n",
    "print(\"exam8: \" , exam8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\n",
       " 3.9487  1.2150\n",
       " 8.5101  3.2009\n",
       "[torch.FloatTensor of size 2x2]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 矩阵乘法, 其中 t() 表示取转置\n",
    "torch.mm(exam7, exam8.t())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\n",
       " 0.2148  0.3664  3.3675\n",
       "-0.4273  4.9234 -1.2951\n",
       "[torch.FloatTensor of size 2x3]"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 矩阵对应元素相乘\n",
    "exam7 * exam8"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "跟numpy一样，再Tensor中，也存在Broadcasting\n",
    "\n",
    "当二元操作符左右两边Tensor形状不一样的时候，系统会尝试将其复制到一个共同的形状。例如a的第0维是3, b的第0维是1，那么 a + b这个操作会将b沿着第0维复制3遍。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a: \n",
      " 0\n",
      " 1\n",
      " 2\n",
      "[torch.FloatTensor of size 3x1]\n",
      "\n",
      "b: \n",
      " 0  1\n",
      "[torch.FloatTensor of size 1x2]\n",
      "\n",
      "a+b: \n",
      " 0  1\n",
      " 1  2\n",
      " 2  3\n",
      "[torch.FloatTensor of size 3x2]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "a = torch.arange(0, 3).view(3, 1)\n",
    "b = torch.arange(0, 2).view(1, 2)\n",
    "print(\"a:\", a)\n",
    "print(\"b:\", b)\n",
    "print(\"a+b:\", a + b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tensor和Numpy的相互转换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " 1  1  1\n",
      " 1  1  1\n",
      "[torch.DoubleTensor of size 2x3]\n",
      "\n",
      "[[ 1.  1.  1.]\n",
      " [ 1.  1.  1.]]\n"
     ]
    }
   ],
   "source": [
    "x = np.ones((2, 3))\n",
    "y = torch.from_numpy(x) # 从numpy -> torch.Tensor\n",
    "print(y)\n",
    "z = y.numpy() # 从torch.Tensor -> numpy\n",
    "print(z)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**常用操作**\n",
    "\n",
    "unsqueeze() 可以让我们把一个向量变成矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " 1\n",
      " 2\n",
      " 3\n",
      " 4\n",
      "[torch.FloatTensor of size 4]\n",
      "\n",
      "\n",
      " 1  2  3  4\n",
      "[torch.FloatTensor of size 1x4]\n",
      "\n",
      "\n",
      " 1\n",
      " 2\n",
      " 3\n",
      " 4\n",
      "[torch.FloatTensor of size 4x1]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "x_u = torch.Tensor([1, 2, 3, 4])\n",
    "print(x_u)\n",
    "x_u_1 = torch.unsqueeze(x_u, 0)\n",
    "print(x_u_1)\n",
    "x_u_2 = torch.unsqueeze(x_u, 1)\n",
    "print(x_u_2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "squeeze() 可以让我们把一个矩阵变成向量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " 1  2  3  4\n",
      "[torch.FloatTensor of size 1x4]\n",
      "\n",
      "\n",
      " 1\n",
      " 2\n",
      " 3\n",
      " 4\n",
      "[torch.FloatTensor of size 4]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "x_sq = torch.Tensor([[1, 2, 3, 4]])\n",
    "print(x_sq)\n",
    "x_sq_1 = torch.squeeze(x_u, 0)\n",
    "print(x_sq_1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "stack() 可以让我们把很多个矩阵\"堆\"在一起形成一个新的高维矩阵。\n",
    "\n",
    "比如，我们有 10 个 (5, 12)的 Tensor， 我们希望把他们堆在一起形成 (10, 5, 12)的Tensor，我们就可以使用 stack"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "每个 tensor 的维度为： torch.Size([5, 12])\n",
      "整个 sequence 的长度为 10\n",
      "stack 整个 sequence 之后得到的结果为： torch.Size([10, 5, 12])\n"
     ]
    }
   ],
   "source": [
    "x_sta = []\n",
    "\n",
    "num = 10\n",
    "\n",
    "for i in range(num):\n",
    "    temp = torch.randn((5, 12))\n",
    "    x_sta.append(temp)\n",
    "    if i == 5:\n",
    "        print(\"每个 tensor 的维度为：\", temp.size())\n",
    "        \n",
    "print(\"整个 sequence 的长度为\", len(x_sta))\n",
    "\n",
    "x_sta_1 = torch.stack(x_sta)\n",
    "\n",
    "print(\"stack 整个 sequence 之后得到的结果为：\", x_sta_1.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最后，这里只是一个引子，还有很多很多的操作，可以在pyTorch官方文档上查阅  [torch.Tensor API](http://pytorch.org/docs/master/tensors.html)"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python [conda root]",
   "language": "python",
   "name": "conda-root-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
